package com.fit.utils.se;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 双向加密(可以将加密前的数据解密出来)
 * 对称加密工具(加密和解密用的 密钥 必须是同一个密钥)
 * AES 加密与解密
 * DES 加密与解密
 * TDES 加密与解密(3DES)  
 * @author hcl
 */
public class SymmetricEncryptUtil {
	
	private static Logger log = LoggerFactory.getLogger(SymmetricEncryptUtil.class);
	
	/**
	 * 默认为UTF-8的编码
	 */
	private final static String DEFAULT_CHARACTER_ENCODING = "UTF-8";
	
	
	
    /** //////////////////////////////////////////////////////////
     * AES加密 与解密
     * //////////////////////////////////////////////////////////
     */
    private static final String AES_KEY_ALGORITHM = "AES"; // 秘钥加密算法

    /**
     * 算法名称/加密模式(共有以下四种工作模式)/填充方式(共有3中填充模式)
     * 加密模式：
	     * ECB：电子密码本模式
	     * CBC：加密分组链接模式
	     * CFB：加密反馈模式
	     * OFB：输出反馈模式
	 * 填充方式：
	     * NoPadding
	     * PKCS5Padding
	     * ISO10126Padding
     */
    public static final String AES_CIPHER_ALGORITHM = "AES";//public static final String AES_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
	
    
    /**
     * 生成AES秘钥(根据key生成一个固定的密钥,长度16)
     *
     * @param key 秘钥
     * @return AES秘钥
     */
    public static byte[] aesKey(byte[] key) {
		byte[] result = null;
		try {
			KeyGenerator kg = KeyGenerator.getInstance(AES_KEY_ALGORITHM);
			SecureRandom secureRandom = (null == key || key.length == 0) ? new SecureRandom() : new SecureRandom(key);
			kg.init(secureRandom);
			SecretKey secretKey = kg.generateKey();
			result = secretKey.getEncoded();
		} catch (NoSuchAlgorithmException e) {
			log.error("生成AES秘钥异常！", e);
		}
		
		return result;
    }
    
    
    
    /**
     * 生成AES秘钥(随机密钥,长度16)
     *
     * @return AES秘钥
     */
    public static byte[] aesKey() {
        return SymmetricEncryptUtil.aesKey(null);
    }
    
    
    
    
    /**
     * AES加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 加密后的byte数组
     */
    public static byte[] aesEncrypt(String data, byte[] key, String encoding) {
    	byte[] result = null;
		try {
			SecretKey secretkey = new SecretKeySpec(key, AES_KEY_ALGORITHM);
			Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, secretkey);
	        result = cipher.doFinal(data.getBytes(encoding));
		} catch (GeneralSecurityException e) {
			log.error("AES加密异常！",e);
		} catch (UnsupportedEncodingException e) {
			log.error("AES加密异常！",e);
		} 
        return result;
    }

    /**
     * AES加密
     *
     * @param data     需要加密的字符串
     * @param key      秘钥
     * @return 加密后的byte数组
     */
    public static byte[] aesEncrypt(String data, byte[] key){
        return SymmetricEncryptUtil.aesEncrypt(data, key, DEFAULT_CHARACTER_ENCODING);
    }

    
    
    /**
     * AES解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 解密后的数据
     */
    public static String aesDecrypt(byte[] data, byte[] key,String encoding){
        String result = null;
		try {
			SecretKey secretkey = new SecretKeySpec(key, AES_KEY_ALGORITHM);
			Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, secretkey);
		    result = new String(cipher.doFinal(data),encoding);
		} catch (GeneralSecurityException e) {
			log.error("AES解密异常！",e);
		} catch (UnsupportedEncodingException e) {
			log.error("AES解密异常！",e);
		}
        return result;
    }

    /**
     * AES解密
     *
     * @param data     需要解密的十六进制字符串
     * @param key      秘钥
     * @return 解密后的原始字符串
     */
    public static String aesDecrypt(byte[] data, byte[] key)  {
        return SymmetricEncryptUtil.aesDecrypt(data, key, DEFAULT_CHARACTER_ENCODING);
    }

	
	
	
    // //////////////////////////////////////////////////////////
    // DES加密 与解密
    // //////////////////////////////////////////////////////////

	
	
	/**
	 DES加密介绍
	      DES是一种对称加密算法，所谓对称加密算法即：加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究，
	 后来被美国政府正式采用，之后开始广泛流传，但是近些年使用越来越少，因为DES使用56位密钥，以现代计算能力，
	 24小时内即可被破解。虽然如此，在某些简单应用中，我们还是可以使用DES加密算法，本文简单讲解DES的JAVA实现
	 。
	 注意：DES加密和解密过程中，密钥长度必须大于等于8
	 */
	
	/**
	 * 算法名称
	 */
	private static final String DES_KEY_ALGORITHM = "DES";
	
    /**
     * 算法名称/加密模式(共有以下四种工作模式)/填充方式(共有3中填充模式)
     * 加密模式：
	     * ECB：电子密码本模式
	     * CBC：加密分组链接模式
	     * CFB：加密反馈模式
	     * OFB：输出反馈模式
     * 填充方式：
	     * NoPadding
	     * PKCS5Padding
	     * ISO10126Padding
     */
	public static final String DES_CIPHER_ALGORITHM = "DES";// public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
	
	
	/**
     * 生成DES秘钥(根据key生成一个固定的密钥,长度8)
     *
     * @param key 秘钥
     * @return DES秘钥 byte数组
     */
    public static byte[] desKey(byte[] key)  {
    	byte[] result = null;
		try {
			KeyGenerator kg = KeyGenerator.getInstance(DES_KEY_ALGORITHM);
			SecureRandom secureRandom = (null == key || key.length == 0) ? new SecureRandom() : new SecureRandom(key);
		    kg.init(secureRandom);
	        SecretKey secretKey = kg.generateKey();
	        result = secretKey.getEncoded();
		} catch (NoSuchAlgorithmException e) {
			log.error("生成DES秘钥异常！",e);
		}
        return result;
    }
	
	
	/**
     * 生成DES秘钥(随机密钥,长度8)
     * @return DES秘钥 byte数组
     */
    public static byte[] desKey() {
        return SymmetricEncryptUtil.desKey(null);
    }

 
	/**
	 * DES加密(解密时,必须用加密时的密钥才能将此字符串解密出来,不然会抛异常)
	 * @param content 待加密的内容
	 * @param encryptKey 加密密钥,长度必须大于等于8
	 * @param encoding 编码
	 * @return 加密后的byte数组
	 */
	public static byte[] desEncrypt(String content, byte[] encryptKey,String encoding) {
		byte[] result = null;
		
		try {
			// DES算法要求有一个可信任的随机数源
			SecureRandom random = new SecureRandom();
			DESKeySpec desKey = new DESKeySpec(encryptKey);
			//创建一个密匙工厂，然后用它把DESKeySpec转换成
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_KEY_ALGORITHM);
			SecretKey securekey = keyFactory.generateSecret(desKey);
			//Cipher对象实际完成加密操作
			Cipher cipher = Cipher.getInstance(DES_CIPHER_ALGORITHM);
			//用密匙初始化Cipher对象
			cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
			//现在，获取数据并加密
			//正式执行加密操作
			result = cipher.doFinal(content.getBytes(encoding));
		} catch (GeneralSecurityException e) {
			log.error("DES加密解密异常！",e);
		} catch (UnsupportedEncodingException e) {
			log.error("DES加密解密异常！",e);
		} 
		return result;
	}
	
	/**
	 * DES加密(解密时,必须用加密时的密钥才能将此字符串解密出来,不然会抛异常)
	 * @param content 待加密的内容
	 * @param encryptKey 加密密钥
	 * @return 加密后的byte数组
	 */
	public static byte[] desEncrypt(String content, byte[] encryptKey) {
		return SymmetricEncryptUtil.desEncrypt(content, encryptKey, DEFAULT_CHARACTER_ENCODING);
	}
	
	
	
	/**
	 * DES解密(解密失败返回null)
	 * 
	 * @param encryptBytes 待解密的byte[]
	 * @param decryptKey 解密密钥
	 * @param encoding 编码
	 * @return 解密后的String
	 */
	public static String desDecrypt(byte[] encryptBytes, byte[] decryptKey,String encoding){
		String result = null;
		try {
			// DES算法要求有一个可信任的随机数源
			SecureRandom random = new SecureRandom();
			// 创建一个DESKeySpec对象
			DESKeySpec desKey = new DESKeySpec(decryptKey);
			// 创建一个密匙工厂
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_KEY_ALGORITHM);
			// 将DESKeySpec对象转换成SecretKey对象
			SecretKey securekey = keyFactory.generateSecret(desKey);
			// Cipher对象实际完成解密操作
			Cipher cipher = Cipher.getInstance(DES_CIPHER_ALGORITHM);
			// 用密匙初始化Cipher对象
			cipher.init(Cipher.DECRYPT_MODE, securekey, random);
			// 真正开始解密操作
			result = new String(cipher.doFinal(encryptBytes),encoding);
		} catch (GeneralSecurityException e) {
			log.error("DES解密异常！",e);
		} catch (UnsupportedEncodingException e) {
			log.error("DES解密异常！",e);
		}
		
		return result;
	}
	
	/**
	 * DES解密(解密失败返回null)
	 * 
	 * @param encryptBytes 待解密的byte[]
	 * @param decryptKey 解密密钥
	 * @return 解密后的String
	 */
	public static String desDecrypt(byte[] encryptBytes, byte[] decryptKey) {
		return SymmetricEncryptUtil.desDecrypt(encryptBytes, decryptKey, DEFAULT_CHARACTER_ENCODING);
	}
	
	
	
	
    // //////////////////////////////////////////////////////////
    // 3DES加密解密
    // //////////////////////////////////////////////////////////
    private static final String TDES_KEY_ALGORITHM = "DESede";

    /**
     * 算法名称/加密模式(共有以下四种工作模式)/填充方式(共有3中填充模式)
     * 加密模式：
	     * ECB：电子密码本模式
	     * CBC：加密分组链接模式
	     * CFB：加密反馈模式
	     * OFB：输出反馈模式
	 * 填充方式：
	     * NoPadding
	     * PKCS5Padding
	     * ISO10126Padding
     */
    public static final String TDES_CIPHER_ALGORITHM = "DESede";// public static final String TDES_CIPHER_ALGORITHM = "DESede/CBC/NoPadding";
	
    

    /**
     * 生成TDES秘钥(根据key生成一个固定的密钥,长度24)
     *
     * @param key 秘钥
     * @return TDES秘钥 byte数组
     */
    public static byte[] tdesKey(byte[] key) {
    	byte[] result = null;
		try {
			KeyGenerator kg = KeyGenerator.getInstance(TDES_KEY_ALGORITHM);
			 SecureRandom secureRandom = (null == key || key.length == 0) ? new SecureRandom() : new SecureRandom(key);
	        kg.init(secureRandom);
	        SecretKey secretKey = kg.generateKey();
	        result = secretKey.getEncoded();
		} catch (NoSuchAlgorithmException e) {
			log.error("生成TDES秘钥异常!",e);
		}
        return result;
    }
    
    /**
     * 生成TDES秘钥(随机密钥,长度24)
     *
     * @return TDES秘钥 byte数组
     */
    public static byte[] tdesKey() {
        return SymmetricEncryptUtil.tdesKey(null);
    }
    

    /**
     * TDES加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 加密后的byte数组
     */
    public static byte[] tdesEncrypt(String data, byte[] key,String encoding)  {
        byte[] result = null;
        try{
	    	SecretKey deskey = new SecretKeySpec(key, TDES_KEY_ALGORITHM);
	    	Cipher cipher = Cipher.getInstance(TDES_CIPHER_ALGORITHM);
	        cipher.init(Cipher.ENCRYPT_MODE, deskey);
	        result = cipher.doFinal(data.getBytes(encoding));
        }catch(GeneralSecurityException e){
        	log.error("3DES加密异常！", e);
        } catch (UnsupportedEncodingException e) {
			log.error("3DES加密异常！", e);
		}
        return result;
    }

    /**
     * TDES加密
     *
     * @param data     需要加密的字符串
     * @param key      秘钥
     * @return 加密后的byte数组
     */
    public static byte[] tdesEncrypt(String data, byte[] key) {
    	return SymmetricEncryptUtil.tdesEncrypt(data, key, DEFAULT_CHARACTER_ENCODING);
    }

    
    
    

    /**
     * TDES解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 解密后的原始字符串
     */
    public static String tdesDecrypt(byte[] data, byte[] key,String encoding)  {
        String result = null;
        try{
	    	SecretKeySpec deskey = new SecretKeySpec(key, TDES_KEY_ALGORITHM);
	    	Cipher cipher = Cipher.getInstance(TDES_CIPHER_ALGORITHM);
	        cipher.init(Cipher.DECRYPT_MODE, deskey);
	        result = new String(cipher.doFinal(data),encoding);
        }catch(GeneralSecurityException e){
        	log.error("3DES解密异常！", e);
        } catch (UnsupportedEncodingException e) {
        	log.error("3DES解密异常！", e);
		}
        return result;
    }

    /**
     * TDES解密
     *
     * @param data     需要解密的十六进制字符串
     * @param key      秘钥
     * @return 解密后的原始字符串
     */
    public static String tdesDecrypt(byte[] data, byte[] key) {
        return SymmetricEncryptUtil.tdesDecrypt(data, key, DEFAULT_CHARACTER_ENCODING);
    }
}
